import * as THREE from "three";
import * as TWEEN from "three/examples/jsm/libs/tween.module.js";
import { random } from "./utils"
import * as d3 from 'd3'
import {
  CSS2DRenderer,
  CSS2DObject,
} from "three/examples/jsm/renderers/CSS2DRenderer.js";
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader.js";
// 导入后期效果合成器
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer";
// three框架本身自带效果
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
import { DotScreenPass } from "three/examples/jsm/postprocessing/DotScreenPass";
import { SMAAPass } from "three/examples/jsm/postprocessing/SMAAPass";
import { SSAARenderPass } from "three/examples/jsm/postprocessing/SSAARenderPass";
import { GlitchPass } from "three/examples/jsm/postprocessing/GlitchPass";
import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass";
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass";
import { SSRPass } from "three/examples/jsm/postprocessing/SSRPass.js";
import { GammaCorrectionShader } from "three/examples/jsm/shaders/GammaCorrectionShader.js";
import { ReflectorForSSRPass } from "three/examples/jsm/objects/ReflectorForSSRPass.js";

import gsap from "gsap";
import useSequenceFrameAnimate from "./useSequenceFrameAnimate"



export default class ThreePlus {
  constructor(selector) {
    this.clock = new THREE.Clock();
    this.domElement = document.querySelector(selector);
    this.width = this.domElement.clientWidth;
    this.height = this.domElement.clientHeight;

    // const Rcolor = new THREE.Color(Math.random() * 0xFFFFFF)
    this.lineColor = new THREE.Color(0x7fecff)
    this.mapColor = new THREE.Color(0xb4eeea)
    this.mapColorCeMian = new THREE.Color(0x123024)
    this.init();
  }
  init() {
    this.initScene(); 
    this.initCamera();
    this.initCSS2DRender()
    this.initRenderer();  
    this.initControl();
    this.render();
    this.initLight()
    this.particleArr = this.initParticle() 

  }
  initScene() {
    this.scene = new THREE.Scene();
  }
  initCamera() {
    this.camera = new THREE.PerspectiveCamera(
      45,
      window.innerHeight / window.innerHeight,
      0.1,
      100000,
    );
    this.camera.position.set(0, 8, 0)
    this.camera.lookAt(0, 0, 0);
    this.camera.aspect = this.width / this.height;
    this.camera.updateProjectionMatrix();
  }
  initRenderer() {
    this.renderer = new THREE.WebGLRenderer({
      logarithmicDepthBuffer: true, 
      antialias: true, 
      alpha: true 
    });
    this.renderer.setSize(this.width, this.height); 
    this.renderer.shadowMap.enabled = true; 

    this.renderer.outputEncoding = THREE.sRGBEncoding;
    this.renderer.physicallyCorrectLights = true; 
    this.renderer.toneMapping = THREE.ACESFilmicToneMapping; 
    this.renderer.toneMappingExposure = 2;
    this.renderer.sortObjects = true;
    this.domElement.appendChild(this.renderer.domElement);
  }
  initControl() {
    this.control = new OrbitControls(this.camera, this.labelRenderer.domElement);
    this.control.enableDamping = true;

    this.control.minPolarAngle = - Math.PI / 4;
    this.control.maxPolarAngle = Math.PI / 2;
  }
  render() {
    this.renderer.render(this.scene, this.camera);
    this.labelRenderer.render(this.scene, this.camera);
    requestAnimationFrame(this.render.bind(this));
    if (this.rotatingApertureMesh) {
      this.rotatingApertureMesh.rotation.z += 0.0005
    }
    if (this.rotatingPointMesh) {
      this.rotatingPointMesh.rotation.z -= 0.0005
    }
    if (this.particleArr?.length) {
      for (let i = 0; i < this.particleArr.length; i++) {
        this.particleArr[i].updateSequenceFrame()
        this.particleArr[i].position.y += 0.01
        if (this.particleArr[i].position.y >= 6) {
          this.particleArr[i].position.y = -6
        }
      }
    }

    if (this.css2dRender) {
      this.css2dRender.render(this.scene, this.camera)
    }

    this.control.update();




    TWEEN.update()
  }
  addAxesHelper() {
    const axesHelper = new THREE.AxesHelper(3)
    this.scene.add(axesHelper)
  }
  initEffect() {
    this.effectComposer = new EffectComposer(this.renderer);
    this.effectComposer.setSize(window.innerWidth, window.innerHeight);

    const renderPass = new RenderPass(this.scene, this.camera);
    this.effectComposer.addPass(renderPass);


    const smaaPass = new SMAAPass();
    this.effectComposer.addPass(smaaPass);


  }

  addClick() {
    this.raycaster = new THREE.Raycaster();
    this.mouse = new THREE.Vector2();

    this.domElement.addEventListener("click", (event) => {
      this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
      this.mouse.y = -((event.clientY / window.innerHeight) * 2 - 1);

      this.raycaster.setFromCamera(this.mouse, this.camera);

      event.mesh = this.mesh;
      event.alarm = this;

      const intersects = this.raycaster.intersectObject(this.mesh);
      if (intersects.length > 0) {
        this.fns.forEach((fn) => {
          fn(event);
        });
      }
    });
  }

  addAlarmSprite(img, position = { x: -1.8, z: 3 }, color = 0xffffff) {
    const textureLoader = new THREE.TextureLoader();
    const map = textureLoader.load(img);
    let material = new THREE.SpriteMaterial({
      map: map,
      color: color,
      transparent: true,
      depthTest: false,
    });

    let mesh = new THREE.Sprite(material);

    mesh.position.set(position.x, position.y, 0.0);
    mesh.scale.set(0.14, 0.14, 0.14)
    this.scene.add(mesh)


  }

  initRotatingAperture() {
    const texture = new THREE.TextureLoader()
    const rotatingApertureTexture = texture.load("/data/map/rotatingAperture.png")
    let plane = new THREE.PlaneGeometry(6, 6)
    let material = new THREE.MeshBasicMaterial({
      map: rotatingApertureTexture,
      transparent: true,
      opacity: 1,
      depthTest: true,
      side: THREE.DoubleSide
    })
    let mesh = new THREE.Mesh(plane, material)
    mesh.position.set(0, -0.04, 0)
    mesh.scale.set(1.1, 1.1, 1.1)
    mesh.rotation.x = -Math.PI / 2;
    mesh.renderOrder = 0
    this.scene.add(mesh)
    return mesh
  }

  initRotatingPoin() {
    const texture = new THREE.TextureLoader()
    const rotatingPointTexture = texture.load("/data/map/rotating-point2.png")
    let plane = new THREE.CircleGeometry(2.6, 32)
    let material = new THREE.MeshBasicMaterial({
      map: rotatingPointTexture,
      transparent: true,
      opacity: 1,
      depthTest: true,
      side: THREE.DoubleSide
    })
    let mesh = new THREE.Mesh(plane, material)
    mesh.position.set(0, -0.06, 0)
    // mesh.scale.set(1.1, 1.1, 1.1)
    mesh.rotation.x = -Math.PI / 2;
    mesh.renderOrder = 1
    this.scene.add(mesh)
    return mesh
  }


  initSceneBg() {
    const texture = new THREE.TextureLoader()
    const sceneBg = texture.load("/data/map/bg.png")
    let plane = new THREE.PlaneGeometry(30, 30)
    let material = new THREE.MeshPhongMaterial({
      // color: 0x061920,
      color: 0xffffff,
      map: sceneBg,
      transparent: true,
      opacity: 1,
      depthTest: true,
      side: THREE.DoubleSide
    })

    let mesh = new THREE.Mesh(plane, material)
    mesh.rotation.x = (-Math.PI / 2);
    mesh.renderOrder = 2
    mesh.position.set(0, -0.02, 0)
    this.scene.add(mesh)
  }

  initCirclePoint() {
    const texture = new THREE.TextureLoader()
    const circlePoint = texture.load("/data/map/circle-point.png")
    let plane = new THREE.PlaneGeometry(6, 6)
    let material = new THREE.MeshPhongMaterial({
      color: 0x00ffff,
      map: circlePoint,
      transparent: true,
      opacity: 1,
      side: THREE.DoubleSide
      // depthTest: false,
    })
    let mesh = new THREE.Mesh(plane, material)
    mesh.rotation.x = (Math.PI / 2);
    mesh.renderOrder = 3
    mesh.position.set(0, 0, 0)
    this.scene.add(mesh)
  }

  initLight() {
    let directionalLight1 = new THREE.DirectionalLight(0x7af4ff, 1)
    directionalLight1.position.set(0, 0, 5)
    let directionalLight2 = new THREE.DirectionalLight(0x7af4ff, 1)
    directionalLight2.position.set(0, 0, 5)
    let ambientLight = new THREE.AmbientLight(0x7af4ff, 1)
    this.scene.add(directionalLight1)
    this.scene.add(directionalLight2)
    this.scene.add(ambientLight)
  }

  initParticle() {
    const { createSequenceFrame } = useSequenceFrameAnimate()
    const random = function (min, max) {
      return Math.floor(Math.random() * (max - min + 1)) + min;
    };

    let minX = -4
    let maxX = 4
    let minY = -4
    let maxY = 4
    let minZ = -4
    let maxZ = 4

    let particleArr = []
    for (let i = 0; i < 56; i++) {
      const particle = createSequenceFrame({
        image: "./data/map/上升粒子1.png",
        width: 50,
        height: 59,
        frame: 9,
        column: 9,
        row: 1,
        speed: 0.5,
      })
      let particleScale = random(5, 10) / 1000
      particle.scale.set(particleScale, particleScale, particleScale)
      particle.rotation.x = Math.PI / 2
      particle.rotation.z = -Math.PI / 2
      particle.rotation.y = Math.PI / 2
      let x = random(minX, maxX)
      let y = random(minY, maxY)
      let z = random(minZ, maxZ)
      particle.position.set(x, y, z)
      particleArr.push(particle)
    }
    this.scene.add(...particleArr)
    return particleArr
  }



  initMap() {
    this.map = new THREE.Object3D()
    this.mapGroup = new THREE.Group();
    const textureLoader = new THREE.TextureLoader()
    this.projection1 = d3.geoMercator().center([120.136078, 33.383912]).translate([0, 0, 0]) 
    const loader = new THREE.FileLoader()
    loader.load('./data/map/wuhu.json', (data) => {
      const jsonData = JSON.parse(data)
      this.operationData(jsonData)
    })
  }


  operationData(jsondata) {
    const features = jsondata.features

    features.forEach((feature) => {
      const province = new THREE.Object3D()

      province.properties = feature.properties.name
      const coordinates = feature.geometry.coordinates
      const properties = feature.properties


      if (feature.geometry.type === 'MultiPolygon') {

        coordinates.forEach((coordinate) => {
          coordinate.forEach((rows) => {
            const mesh = this.drawExtrudeMesh(rows, this.mapColor, this.projection1)
            const line = this.lineDraw(rows, this.lineColor, this.projection1, 0.2)
            for (let index = 0; index < 5; index++) {
              let line = this.lineDraw(rows, this.lineColor, this.projection1, index * 0.04)
              // province.add(line)
            }
            mesh.properties = feature.properties.name

            mesh.geometry.computeBoundingSphere();  
            // console.log(mesh.geometry.boundingSphere,'geometry')
            //  const labelDiv =   this.createdLabel(feature.properties.name)
            //  let x = mesh.geometry
            //  console.log(x)

            //  let centerZB = x?.boundingSphere
            //  console.log(centerZB)

            //  labelDiv.position.set(1.092220552265644,-1.8644585013389587,0.3); // 设置这个文字的位置
            //  mesh.add(labelDiv)


            province.add(line)
            this.mapGroup.add(mesh)
            province.add(mesh)
          })
        })
      }

      if (feature.geometry.type === 'Polygon') {

        coordinates.forEach((coordinate) => {

          const mesh = this.drawExtrudeMesh(coordinate, this.mapColor, this.projection1)
          const line = this.lineDraw(coordinate, this.lineColor, this.projection1)
          for (let index = 0; index < 4; index++) {
            let line = this.lineDraw(coordinate, this.lineColor, this.projection1, index * 0.04)
            // province.add(line)
          }
          mesh.properties = feature.properties.name

          province.add(line)
          this.mapGroup.add(mesh)
          province.add(mesh)
        })
      }






      this.map.add(province)
    })
    console.log(this.map, 'province')

    this.cityCenterList = this.map.children.map(v => {
      let name = v.properties
      let z = 0.3
      v.children[1].geometry.computeBoundingSphere();
      let center = v.children[1].geometry.boundingSphere.center

      const labelDiv = this.createdLabel(v.properties)
      labelDiv.position.set(center.x, center.y, 0.3); 
      v.children[1].add(labelDiv)


      let o = {
        x: center.x,
        y: center.y,
        z
      }
      return {
        name,
        o
      }
    })

    console.log(this.cityCenterList)


    this.map.rotation.x = -Math.PI / 2
    this.map.rotation.z = Math.PI / 4
    this.scene.add(this.map)
  }

  lineDraw(polygon, color, projection, z = 8) {
    let linePoints = []
    polygon.forEach((row) => {
      const [x, y] = projection(row)
      linePoints.push(new THREE.Vector3(x, -y, z))
    })
    let lineCurve = new THREE.CatmullRomCurve3(linePoints);

    let geometry = new THREE.TubeGeometry(
      lineCurve,
      200,
      0.004,
      16,
      true
    );
    let material = new THREE.MeshBasicMaterial({
      color,
    });

    // 4/创建飞线物体
    return new THREE.Mesh(geometry, material);






    // const lineGeometry = new THREE.BufferGeometry()
    // const pointsArray = []
    // polygon.forEach((row) => {
    //   const [x, y] = projection(row)
    //   // 创建三维点
    //   pointsArray.push(new THREE.Vector3(x, -y, z))
    // })
    // // 放入多个点
    // lineGeometry.setFromPoints(pointsArray)

    // const lineMaterial = new THREE.LineBasicMaterial({
    //   color,
    // })
    // return new THREE.Line(lineGeometry, lineMaterial)
  }

  drawExtrudeMesh(polygon, color, projection) {
    const shape = new THREE.Shape()
    polygon.forEach((row, i) => {
      const [x, y] = projection(row)
      if (i === 0)
        shape.moveTo(x, -y)

      shape.lineTo(x, -y)
    })
    // 拉伸
    const geometry = new THREE.ExtrudeGeometry(shape, {
      depth: 0.2,
      bevelEnabled: false,
    })


    const texture = new THREE.TextureLoader()
    const textureMap = texture.load("/data/map/gz-map.jpg")
    const texturefxMap = texture.load("/data/map/gz-map-fx.jpg")

    textureMap.wrapS = texturefxMap.wrapS = THREE.RepeatWrapping
    textureMap.wrapT = texturefxMap.wrapT = THREE.RepeatWrapping
    textureMap.flipY = texturefxMap.flipY = false
    textureMap.rotation = texturefxMap.rotation = THREE.MathUtils.degToRad(45)
    const scale = 0.128
    textureMap.repeat.set(scale, scale)
    texturefxMap.repeat.set(scale, scale)
    const topFaceMaterial = new THREE.MeshPhongMaterial({
      map: textureMap,
      color: this.mapColor,
      combine: THREE.MultiplyOperation,
      transparent: true,
      opacity: 1,
    })
    const sideMaterial = new THREE.MeshLambertMaterial({
      color: this.mapColorCeMian,
      transparent: true,
      opacity: 0.9,
    })


    return new THREE.Mesh(geometry, [topFaceMaterial, sideMaterial])
    // return new THREE.Mesh(geometry,material)
  }


  initCSS2DRender() {
    // 实例化css2d的渲染器
    this.labelRenderer = new CSS2DRenderer();
    this.labelRenderer.setSize(window.innerWidth, window.innerHeight); //设置css2d渲染器尺寸
    document.body.appendChild(this.labelRenderer.domElement)
    this.labelRenderer.domElement.style.position = 'fixed'; // 设置css2d渲染器为固定定位
    this.labelRenderer.domElement.style.top = '0px';
    this.labelRenderer.domElement.style.left = '0px';
    this.labelRenderer.domElement.style.zIndex = '1000';
   
  }

  createdLabel(name) {
   
    const earthDiv = document.createElement('div'); 
    earthDiv.className = "label"; 
    earthDiv.innerHTML = name;   
    const earthLabel = new CSS2DObject(earthDiv);
    return earthLabel
  }

  setMapdepth(name) {
    console.log(this.mapGroup)
    // let item = this.map.children.find(v=>name == v.properties)
    // item.children[1].geometry.parameters.options.depth = 1

  }



}
